package mge.particles 
{
    import away3d.containers.View3D;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.SpreadMethod;
    import flash.display.Sprite;
    import flash.geom.ColorTransform;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.geom.Vector3D;
    import mge.Timer;
    
	/**
   * ...
   * @author ivan
   */
  public class ParticleSystem 
  {
    
    public function ParticleSystem(bitmap:Bitmap, view:View3D) 
    {
      this.bitmap = bitmap;
      this.parent = parent;
      this.view = view;
      
      timer = new Timer(1000);
      timer.start();
      systemTmr = new Timer(1000);
      bitmapIndex = 0;
    }
    
    public function update(timeScale:Number = 1):void
    {
      if (!started) return;
      
      var delta:Number = timer.getDelta() * timeScale;
      
      if (!systemTmr.finished())
      {        
        var shouldHaveEmittedNum:int = 1 + (systemLifeTime * systemTmr.getDelta()) * emission;
        while (emmited < shouldHaveEmittedNum)
        {
          addParticle();
        }
      }
      else 
      {
          if (particles.length == 0) started = false;
          if (continuous) fire();
      }
      
      for (var i:int = 0; i < particles.length; i++)
      {
        var p:Particle = particles[i];
        p.update(delta);
        if (p.currentLife >= p.lifeTime)
        {
            p.clear();
            particles.splice(i--, 1);
            pool.push(p);
        }
      }
        
      timer.start();
    }
    
    public function fire():void
    {        
        timer.start();
        systemTmr = new Timer(systemLifeTime*1000);
        systemTmr.start();
        started = true;
        emmited = 0;
    }
    
    private function addParticle():void
    {
      var p:Particle;
      
      if (pool.length == 0)
        p = new Particle(tile, view);
      else
      {
          p = pool.pop();
          p.revive(tile);
      }
        
      // Position
      p.position = position.clone();
      
      // Gravity
      p.gravity = gravityNormDir.clone();
      p.gravity.scaleBy(random(gravityMin, gravityMax));
      
      // Note:
      // Velocity = (rv * spread/360) + vn * (360-spread)/360
      // Where rv=random vector, vn=velocity normalized (both normalized).
      
      // Velocity
      var vn:Vector3D = velocityNormDir.clone();
      vn.normalize();
      vn.scaleBy( (360 - spread) / 360);
      
      // Velocity is affected by spread
      var rv:Vector3D = new Vector3D(random( -1, 1), random( -1, 1), random( -1, 1));
      rv.normalize();
      rv.scaleBy(spread/360);
      
      var v:Vector3D = new Vector3D;
      v = v.add(vn);
      v = v.add(rv);
      
      v.scaleBy(random(velocityMin, velocityMax));
      p.velocity = v;
      
      p.radialAcceleration = random(radialAccelerationMin, radialAccelerationMax);
      
      p.lifeTime = random(particleLifeTimeMin, particleLifeTimeMax);
      
      if (scaleStart > scaleEnd)
      {
        var maxVar:Number = (scaleStart - scaleEnd) * scaleVar * Math.random();
        p.scaleStart = scaleStart - maxVar;
        p.scaleEnd = scaleEnd + maxVar;
      }
      else
      {
        maxVar = (scaleEnd - scaleStart) * scaleVar * Math.random();
        p.scaleStart = scaleStart + maxVar;
        p.scaleEnd = scaleEnd - maxVar;
      }
            
      p.colorStart = colorStart;
      p.colorEnd = colorEnd;
      
      p.spinStart = spinStart + (Math.random() * spinVar - spinVar * 0.5);
      p.spinEnd = spinEnd + (Math.random() * spinVar - spinVar * 0.5);
      
      particles.push(p);
      
      emmited++;
    }
    
    private function random(min:Number, max:Number):Number
    {
        return (min + ((max - min) * Math.random()));
    }
    
    
    // System parameters                                        // Ranges
    // ------------------------------------------------------------------------
    public var systemLifeTime:Number = 1;                        // (0,+inf)
    public var emission:int = 10;                                // (0,+inf)
    public var continuous:Boolean;                               // true, false
    
    public var particleLifeTimeMax:Number = 1;                   // (0,+inf)
    public var particleLifeTimeMin:Number = 0;                   // (0,+inf)
    
    public var position:Vector3D = new Vector3D();               // any
    
    
    // Movement parameters                                       // Ranges
    // ------------------------------------------------------------------------
    public var radialAccelerationMax:Number = 0;                 // (-inf,+inf)
    public var radialAccelerationMin:Number = 0;                 // (-inf,+inf)
    
    public var gravityNormDir:Vector3D = new Vector3D(0, 1, 0);  // normalized vector
    public var gravityMax:Number = 0;                            // (-inf,+inf)
    public var gravityMin:Number = 0;                            // (-inf,+inf)
    
    public var velocityNormDir:Vector3D = new Vector3D(0, -1, 0);// normalized vector
    public var velocityMax:Number = 1;                           // (-inf,+inf)
    public var velocityMin:Number = 1;                           // (-inf,+inf)
                                
    public var spread:Number = 0;                                // spread angle [0,360]

    
    // Particle appareance                                       // Ranges
    // ------------------------------------------------------------------------
    public var scaleStart:Number = 1;                            // (-inf,+inf)
    public var scaleEnd:Number = 1;                              // (-inf,+inf)
    public var scaleVar:Number = 0;                              // [0,1]
                                
    public var colorStart:uint;                                  // [0x00000000, 0xFFFFFFFF]
    public var colorEnd:uint;                                    // [0x00000000, 0xFFFFFFFF]
    
    public var spinStart:Number = 0;                             // (-inf,+inf)
    public var spinEnd:Number = 0;                               // (-inf,+inf)
    public var spinVar:Number = 0;                               // (-inf,+inf)
    
    
    public function get bitmapIndex():int { return _bitmapIndex; }
    public function set bitmapIndex(val:int):void
    {
        _bitmapIndex = val;
        var w:int = bitmap.width / 4;
        var h:int = bitmap.height / 4;
        var x:int = ((int)(_bitmapIndex / 4)) * w;
        var y:int = ((int)(_bitmapIndex % 4)) * h;
        
        var bmpData:BitmapData = new BitmapData(w, h);
        
        bmpData.copyPixels(bitmap.bitmapData, new Rectangle(x, y, w, h), new Point(0, 0));
        tile = new Bitmap(bmpData, "auto", true);
    }
    private var _bitmapIndex:int;
    
    private var particles:Vector.<Particle> = new Vector.<Particle>();
    private var pool:Vector.<Particle> = new Vector.<Particle>();
    private var timer:Timer;
    private var systemTmr:Timer;
    private var bitmap:Bitmap;
    private var tile:Bitmap;
    private var parent:Sprite;
    private var emmited:int;
    private var started:Boolean;
    private var view:View3D;
  }

}